#include "configfileoperation.h"
#include <QtXml/QDomNode>
#include <QtXml/QDomElement>
#include <QtXml/QDomDocument>
#include <QtXml/QDomNodeList>
#include <QtXml/QDomText>
#include <QtXml\QDomProcessingInstruction>
#include <QFile>
#include <QStringList>
#include <QTextStream>

namespace CoreBase
{
	ConfigFileOperation* ConfigFileOperation::_configObj = NULL;

	ConfigFileOperation& ConfigFileOperation::GetInstance()
	{
		if(_configObj == NULL)
		{
			_configObj = new ConfigFileOperation;
		}
		return *_configObj;
	}

	ConfigFileOperation::ConfigFileOperation()
	{}

	ConfigFileOperation::~ConfigFileOperation()
	{}

	bool ConfigFileOperation::loadConfigFile(const QString& file)
	{
		QFile xmlFile(file+"\\"+DEFAULT_CONFIG_FILENAME);
		if(!xmlFile.open(QIODevice::ReadWrite))     
		{   
			return false;
		}
		QDomDocument domtree; 
		if(!domtree.setContent(&xmlFile))   
		{   
			xmlFile.close(); 
			return false;   
		}
		clearAll();
		QDomElement  root = domtree.documentElement();   
		QDomNodeList  nodelist=root.childNodes();  
		int count=nodelist.length();
		for(int i=0;i<nodelist.length();++i)
		{
			QDomNode childnode = nodelist.item(i);
			if(childnode.nodeName() == "element")
			{
				QString name = "";
				QString value = "";
				QString valuetype = "";
				for(int j=0;j< childnode.childNodes().length();j++)
				{
					if(childnode.childNodes().item(j).nodeName() == XML_ELEMENT_NAME)
					{
						name = childnode.childNodes().item(j).toElement().text();
					}
					else
					{
						valuetype = childnode.childNodes().item(j).nodeName();
						value = childnode.childNodes().item(j).toElement().text();
					}
				}
				if(name!="" && value!="" && valuetype!="")
					add(name,valuetype,value);
			}
		}
	}

	void ConfigFileOperation::clearAll()
	{
		_intValueMap.clear();
		_floatValueMap.clear();
		_qstringValueMap.clear();
		_vec2ValueMap.clear();
		_vec3ValueMap.clear();
		_vec4ValueMap.clear();
	}

	void ConfigFileOperation::add(const QString& name,const QString& valuetype,const QString& value)
	{
		if(valuetype == "int")
		{
			int intvalue = value.toInt();
			addIntValue(name,intvalue);
		}
		else if(valuetype == "float")
		{
			float floatvalue = value.toFloat();
			addfloatValue(name,floatvalue);
		}
		else if(valuetype == "qstring")
		{
			addQStringValue(name,value);
		}
		else if(valuetype == "vec2")
		{
			QStringList list = value.split(" ",QString::SkipEmptyParts);
			if(list.size() == 2)
			{
				osg::Vec2 vec2(list.at(0).toFloat(),list.at(1).toFloat());
				addVec2Value(name,vec2);
			}
		}
		else if(valuetype == "vec3")
		{
			QStringList list = value.split(" ",QString::SkipEmptyParts);
			if(list.size() == 3)
			{
				osg::Vec3 vec3(list.at(0).toFloat(),list.at(1).toFloat(),list.at(2).toFloat());
				addVec3Value(name,vec3);
			}
		}
		else if(valuetype == "vec4")
		{
			QStringList list = value.split(" ",QString::SkipEmptyParts);
			if(list.size() == 4)
			{
				osg::Vec4 vec4(list.at(0).toFloat(),list.at(1).toFloat(),list.at(2).toFloat(),list.at(3).toFloat());
				addVec4Value(name,vec4);
			}
		}
		else if(valuetype == "bool")
		{
			bool boolvalue = value == "true"?true:false;
			addBoolValue(name,boolvalue);
		}
	}

	bool ConfigFileOperation::writeConfigFile(const QString& file)
	{
		QFile xmlFile(file+"\\"+DEFAULT_CONFIG_FILENAME);
		if(!xmlFile.open(QIODevice::WriteOnly|QIODevice::Text))     
		{   
			//log
			return false;
		} 
		QDomDocument domtree; 
		QDomText text;
		domtree.documentElement().clear();
		QDomProcessingInstruction instruction;
		instruction = domtree.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
		domtree.appendChild( instruction);
		//map
		QDomElement mapelement = domtree.createElement("elements");
		domtree.appendChild(mapelement);
		//intmap
		QMap<QString,int>::Iterator intiter = _intValueMap.begin();
		for(;intiter!=_intValueMap.end();++intiter)
		{
			QDomElement intelement = domtree.createElement("element");
			mapelement.appendChild(intelement);
			//name
			QDomElement intnameelement = domtree.createElement(XML_ELEMENT_NAME);
			intelement.appendChild(intnameelement);
			text = domtree.createTextNode(intiter.key());
			intnameelement.appendChild(text);
			//value
			QDomElement intvalueelement = domtree.createElement("int");
			intelement.appendChild(intvalueelement);
			text = domtree.createTextNode(QString::number(intiter.value()));
			intvalueelement.appendChild(text);
		}
		//floatmap
		QMap<QString,float>::Iterator floatiter = _floatValueMap.begin();
		for(;floatiter!=_floatValueMap.end();++floatiter)
		{
			QDomElement floatelement = domtree.createElement("element");
			mapelement.appendChild(floatelement);
			//name
			QDomElement floatnameelement = domtree.createElement(XML_ELEMENT_NAME);
			floatelement.appendChild(floatnameelement);
			text = domtree.createTextNode(floatiter.key());
			floatnameelement.appendChild(text);
			//value
			QDomElement floatvalueelement = domtree.createElement("float");
			floatelement.appendChild(floatvalueelement);
			text = domtree.createTextNode(QString::number(floatiter.value()));
			floatvalueelement.appendChild(text);
		}
		//qstring
		QMap<QString,QString>::Iterator qstringiter = _qstringValueMap.begin();
		for(;qstringiter!=_qstringValueMap.end();++qstringiter)
		{
			QDomElement qstringelement = domtree.createElement("element");
			mapelement.appendChild(qstringelement);
			//name
			QDomElement qstringnameelement = domtree.createElement(XML_ELEMENT_NAME);
			qstringelement.appendChild(qstringnameelement);
			text = domtree.createTextNode(qstringiter.key());
			qstringnameelement.appendChild(text);
			//value
			QDomElement qstringvalueelement = domtree.createElement("qstring");
			qstringelement.appendChild(qstringvalueelement);
			text = domtree.createTextNode(qstringiter.value());
			qstringvalueelement.appendChild(text);
		}
		//vec2
		QMap<QString,osg::Vec2>::Iterator vec2iter = _vec2ValueMap.begin();
		for(;vec2iter!=_vec2ValueMap.end();++vec2iter)
		{
			QDomElement vec2element = domtree.createElement("element");
			mapelement.appendChild(vec2element);
			//name
			QDomElement vec2nameelement = domtree.createElement(XML_ELEMENT_NAME);
			vec2element.appendChild(vec2nameelement);
			text = domtree.createTextNode(vec2iter.key());
			vec2nameelement.appendChild(text);
			//value
			QDomElement vec2valueelement = domtree.createElement("vec2");
			vec2element.appendChild(vec2valueelement);
			QString vec2string = QString::number(vec2iter.value().x())+" "+QString::number(vec2iter.value().y());
			text = domtree.createTextNode(vec2string);
			vec2valueelement.appendChild(text);
		}
		//vec3
		QMap<QString,osg::Vec3>::Iterator vec3iter = _vec3ValueMap.begin();
		for(;vec3iter!=_vec3ValueMap.end();++vec3iter)
		{
			QDomElement vec3element = domtree.createElement("element");
			mapelement.appendChild(vec3element);
			//name
			QDomElement vec3nameelement = domtree.createElement(XML_ELEMENT_NAME);
			vec3element.appendChild(vec3nameelement);
			text = domtree.createTextNode(vec3iter.key());
			vec3nameelement.appendChild(text);
			//value
			QDomElement vec3valueelement = domtree.createElement("vec3");
			vec3element.appendChild(vec3valueelement);
			QString vec3string = QString::number(vec3iter.value().x())+" "+QString::number(vec3iter.value().y())+
					" "+QString::number(vec3iter.value().z());
			text = domtree.createTextNode(vec3string);
			vec3valueelement.appendChild(text);
		}
		//vec4
		QMap<QString,osg::Vec4>::Iterator vec4iter = _vec4ValueMap.begin();
		for(;vec4iter!=_vec4ValueMap.end();++vec4iter)
		{
			QDomElement vec4element = domtree.createElement("element");
			mapelement.appendChild(vec4element);
			//name
			QDomElement vec4nameelement = domtree.createElement(XML_ELEMENT_NAME);
			vec4element.appendChild(vec4nameelement);
			text = domtree.createTextNode(vec4iter.key());
			vec4nameelement.appendChild(text);
			//value
			QDomElement vec4valueelement = domtree.createElement("vec4");
			vec4element.appendChild(vec4valueelement);
			QString vec4string = QString::number(vec4iter.value().r())+" "+QString::number(vec4iter.value().g())+
					" "+QString::number(vec4iter.value().b())+" "+QString::number(vec4iter.value().a());
			text = domtree.createTextNode(vec4string);
			vec4valueelement.appendChild(text);
		}
		QTextStream out(&xmlFile);
		domtree.save(out,4,QDomNode::EncodingFromTextStream);
		xmlFile.close();
		return true;
	}

	void ConfigFileOperation::addIntValue(const QString& name,int value)
	{
		if(!_intValueMap.contains(name))
			_intValueMap.insert(name,value);
		_intValueMap[name] = value;
	}

	void ConfigFileOperation::addfloatValue(const QString& name,float value)
	{
		if(!_floatValueMap.contains(name))
			_floatValueMap.insert(name,value);
		_floatValueMap[name] = value;
	}

	void ConfigFileOperation::addQStringValue(const QString& name,const QString& value)
	{
		if(!_qstringValueMap.contains(name))
			_qstringValueMap.insert(name,value);
		_qstringValueMap[name] = value;
	}

	void ConfigFileOperation::addVec2Value(const QString& name,const osg::Vec2& value)
	{
		if(!_vec2ValueMap.contains(name))
			_vec2ValueMap.insert(name,value);
		_vec2ValueMap[name] = value;
	}

	void ConfigFileOperation::addVec3Value(const QString& name,const osg::Vec3& value)
	{
		if(!_vec3ValueMap.contains(name))
			_vec3ValueMap.insert(name,value);
		_vec3ValueMap[name] = value;
	}

	void ConfigFileOperation::addVec4Value(const QString& name,const osg::Vec4& value)
	{
		if(!_vec4ValueMap.contains(name))
			_vec4ValueMap.insert(name,value);
		_vec4ValueMap[name] = value;
	}

	void ConfigFileOperation::addBoolValue(const QString& name,bool value)
	{
		if(!_boolValueMap.contains(name))
			_boolValueMap.insert(name,value);
		_boolValueMap[name] = value;
	}

	int ConfigFileOperation::getIntValue(const QString& name)
	{
		if(_intValueMap.contains(name))
			return _intValueMap[name];
		return -1;
	}

	float ConfigFileOperation::getfloatValue(const QString& name)
	{
		if(_floatValueMap.contains(name))
			return _floatValueMap[name];
		return -1;
	}

	QString ConfigFileOperation::getQStringValue(const QString& name)
	{
		if(_qstringValueMap.contains(name))
			return _qstringValueMap[name];
		return "null";
	}

	osg::Vec2 ConfigFileOperation::getVec2Value(const QString& name)
	{
		if(_vec2ValueMap.contains(name))
			return _vec2ValueMap[name];
		return osg::Vec2(-1,-1);
	}

	osg::Vec3 ConfigFileOperation::getVec3Value(const QString& name)
	{
		if(_vec3ValueMap.contains(name))
			return _vec3ValueMap[name];
		return osg::Vec3(-1,-1,-1);
	}

	osg::Vec4 ConfigFileOperation::getVec4Value(const QString& name)
	{
		if(_vec4ValueMap.contains(name))
			return _vec4ValueMap[name];
		return osg::Vec4(-1,-1,-1,-1);
	}

	bool ConfigFileOperation::getBoolValue(const QString& name)
	{
		if(_boolValueMap.contains(name))
			return _boolValueMap[name];
		return false;
	}
}